Skip to content

[SPARK-38870][SQL][PYSPARK] Make SparkSession.builder return new builder - #36161

Closed
FurcyPin wants to merge 4 commits into
apache:masterfrom
FurcyPin:FurcyPin/SPARK-38870
Closed

[SPARK-38870][SQL][PYSPARK] Make SparkSession.builder return new builder#36161
FurcyPin wants to merge 4 commits into
apache:masterfrom
FurcyPin:FurcyPin/SPARK-38870

Conversation

@FurcyPin

Copy link
Copy Markdown

What changes were proposed in this pull request?

In Scala, SparkSession.builder returns a new builder each time,
but in Python, it returns the same builder every time, with the
same static options.

Because of this, whenever SparkSession.builder.getOrCreate() is called,
the options set in the very first builder are reapplied.

To fix this, I introduce a @classproperty decorator, that is similar
to the @Property decorator, except that it works with class methods.
Now, whenever SparkSession.builder is called, a new builder is
returned as expected.

I also made the parameter Builder._options non-static, and I removed
Builder._sc which didn't seem used anymore.

Builder._sc was introduced in this commit:
58419b9

And it's only use seems to have been removed by this commit:
88696eb

How was this patch tested?

I updated the Doctests for SparkSession.Builder.getOrCreate and added
Doctests on the classproperty decorator as well.

What changes were proposed in this pull request?

Why are the changes needed?

Does this PR introduce any user-facing change?

How was this patch tested?

@AmplabJenkins

Copy link
Copy Markdown

Can one of the admins verify this patch?

Comment thread python/pyspark/sql/session.py Outdated
Comment thread python/pyspark/sql/session.py Outdated
Comment thread python/pyspark/sql/session.py Outdated
@HyukjinKwon

HyukjinKwon commented Apr 14, 2022

Copy link
Copy Markdown
Member

Looks pretty good. Thanks - this can be a pretty important bug fix in some usecases I believe.

cc @ueshin @viirya @BryanCutler @dongjoon-hyun FYI

Comment thread python/pyspark/sql/session.py Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@viirya viirya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. Wondering why we don't have related bug report before.

@FurcyPin

Copy link
Copy Markdown
Author

This looks good. Wondering why we don't have related bug report before.

Yeah, I am amazed that it hasn't been spotted earlier ^ ^

@FurcyPin
FurcyPin force-pushed the FurcyPin/SPARK-38870 branch from c1f43b9 to d696922 Compare April 14, 2022 07:29
Comment thread python/pyspark/sql/session.py Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you make it as an IDed TODO, @FurcyPin ?
For example, we recommend to use a pattern TODO(SPARK-XXX) with a concrete JIRA ID.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread python/pyspark/sql/session.py Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

@dongjoon-hyun dongjoon-hyun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, LGTM with minor comments.

@HyukjinKwon HyukjinKwon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I am fine as is. LGTM2

@ueshin ueshin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I like returning a different instance each time.

@HyukjinKwon

Copy link
Copy Markdown
Member

@FurcyPin mind enabling https://github.com/FurcyPin/spark/actions/workflows/build_and_test.yml? Apache Spark uses the test results in PR author's forked repository. After enabling it, you might need to rebase it.

@BryanCutler BryanCutler left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@FurcyPin
FurcyPin force-pushed the FurcyPin/SPARK-38870 branch from d696922 to 1ce3ad5 Compare April 15, 2022 07:51
@FurcyPin

Copy link
Copy Markdown
Author

@FurcyPin mind enabling https://github.com/FurcyPin/spark/actions/workflows/build_and_test.yml? Apache Spark uses the test results in PR author's forked repository. After enabling it, you might need to rebase it.

Sure, done.

@FurcyPin

Copy link
Copy Markdown
Author

It looks like the pipeline failed with the following error :

Traceback (most recent call last):
  File "/usr/lib/python3.9/runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/__w/spark/spark/python/pyspark/sql/session.py", line 1227, in <module>
    _test()
  File "/__w/spark/spark/python/pyspark/sql/session.py", line 1216, in _test
    (failure_count, test_count) = doctest.testmod(
  File "/usr/lib/python3.9/doctest.py", line 1955, in testmod
    for test in finder.find(m, name, globs=globs, extraglobs=extraglobs):
  File "/usr/lib/python3.9/doctest.py", line 939, in find
    self._find(tests, obj, name, module, source_lines, globs, {})
  File "/usr/lib/python3.9/doctest.py", line 1001, in _find
    self._find(tests, val, valname, module, source_lines,
  File "/usr/lib/python3.9/doctest.py", line 1028, in _find
    val = getattr(obj, valname).__func__
AttributeError: 'Builder' object has no attribute '__func__'

It's quite strange, I can't reproduce on my side. I'm using Python 3.9.12 and I see the pipeline used Python 3.9.5.
Maybe it's related ?
I won't have the time to investigate further until Tuesday, but if someone have any pointer, I'll be glad to hear it.

@HyukjinKwon

Copy link
Copy Markdown
Member

Yeah, looks like Python version problem. We might have to upgrade Python 3.9 maintenance version.

Comment thread python/pyspark/sql/session.py Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, maybe you can comment this branch out, and create another JIRA to upgrade Python version in CI.

BTW, it would be great if we can actually test and verify that it's Python version problem.

@dongjoon-hyun

Copy link
Copy Markdown
Member

+1 for @HyukjinKwon 's suggestion about the verification.

To @FurcyPin , if this patch broke old Python 3.9.5, that could be considered a regression by the production users.

I'm using Python 3.9.12 and I see the pipeline used Python 3.9.5.

@FurcyPin

Copy link
Copy Markdown
Author

Okay, I instally Python 3.9.5 manually on my laptop, and I confirm that the unit tests are failing with this version, and that they were not failing with Python 3.9.12.

I will try to find a fix.

@FurcyPin

Copy link
Copy Markdown
Author

I think this is the bug I'm running into: python/cpython#28838

Basically, after they made @classmethod and @Property compatible, it caused docstrings to call ._func_ systematically.

A fix has been backported in 3.9 and 3.10. I believe 3.9.6 has the fix.

I see several possible solution:

  1. Add an artificial _func_ hoping it will work around
  2. Wait for the python version in the CI to be bumped to 3.9.6 or higher
  3. Change my if statement like this :
if sys.version_info > (3, 9, 5)

What do you think ?

@HyukjinKwon

Copy link
Copy Markdown
Member

I think you can just file a JIRA to upgrade the Python version in the CI, and just remove

        @classmethod
        @property
        def builder(cls):
            """A class attribute having a :class:`Builder` to construct :class:`SparkSession` instances."""
            return cls.Builder()

for now. We will likely bring it back before Spark 3.4.0 release in any event. Your 3. works too.

@FurcyPin
FurcyPin force-pushed the FurcyPin/SPARK-38870 branch from 1ce3ad5 to 0c0bf73 Compare April 20, 2022 07:56
@FurcyPin

Copy link
Copy Markdown
Author

Okay,

@FurcyPin
FurcyPin force-pushed the FurcyPin/SPARK-38870 branch from 0c0bf73 to 048cf00 Compare April 20, 2022 14:07
@FurcyPin

Copy link
Copy Markdown
Author

I fixed the linter's warnings and I also update SparkSession.builder's docstring to make it reflect the change of behaviour
and look more like Scala's SparkSession.builder description.

@FurcyPin
FurcyPin force-pushed the FurcyPin/SPARK-38870 branch 4 times, most recently from aa30677 to d882889 Compare April 22, 2022 08:48
@FurcyPin

FurcyPin commented Apr 22, 2022

Copy link
Copy Markdown
Author

@HyukjinKwon
I couldn't make all checks pass as I keep being bullied by the python linter.
I had to silence one warning because I couldn't find any way to fix it.
But now the build fails on a file that I didn't even touch...

examples/src/main/python/pagerank.py:79: error: unused "type: ignore" comment

This is referring to this line, which I did not even touch:

url_urls_rank[1][0], url_urls_rank[1][1] # type: ignore[arg-type]

I don't know what to do. Could you please help me ?

@HyukjinKwon

Copy link
Copy Markdown
Member

Weird. That looks unrelated to change. Mind rebasing your master branch? Maybe there are some mypy version pinned in GitHub Actions workflow that cannot be synced when running tests. (thus it's dependent on master branch in your fork)

Furcy Pin added 3 commits April 26, 2022 09:54
## What changes were proposed in this pull request?

In Scala, SparkSession.builder returns a new builder each time,
but in Python, it returns the same builder every time, with the
same static options.

Because of this, whenever SparkSession.builder.getOrCreate() is called,
the options set in the very first builder are reapplied.

To fix this, I introduce a @classproperty decorator, that is similar
to the @Property decorator, except that it works with class methods.
Now, whenever `SparkSession.builder` is called, a new builder is
returned as expected.

I also made the parameter `Builder._options` non-static, and I removed
`Builder._sc` which didn't seem used anymore.

`Builder._sc` was introduced in this commit:
58419b9

And it's only use seems to have been removed by this commit:
88696eb

## How was this patch tested?

I updated the Doctests for SparkSession.Builder.getOrCreate and added
Doctests on the classproperty decorator as well.
## Update of previous commit

Since Python 3.9, the @classmethod decorator is compatible
with the @Property decorator.

This change adds a check on the Python version to use the "proper"
way in 3.9 and beyond, and a TODO to remember cleaning up once
support for Python 3.8 is dropped.
## Update of previous commits

Update docstring for SparkSession.builder, to make it match
with Scala's description.
@FurcyPin
FurcyPin force-pushed the FurcyPin/SPARK-38870 branch from d882889 to 028298e Compare April 26, 2022 07:55
@FurcyPin

FurcyPin commented Apr 26, 2022

Copy link
Copy Markdown
Author

@HyukjinKwon I just rebased and it's still happening.

I did not have this error (but I had other errors) before this commit

Maybe for some obscure reason, the fact that I added # type: ignore in session.py triggered a side effect on pagerank.py ???

Since the linter says unused "type: ignore" comment, I'll try removing it...

Ok. Now mypy passes, but a ton of mypy data tests are now failing...
https://github.com/FurcyPin/spark/runs/6172104928?check_suite_focus=true

I really don't understand how this can be linked to my changes... and yet, the build on the branch master seems to work fine.

Guess I'll have to make another branch an push changes one by one until I find what's really happening...

@FurcyPin
FurcyPin force-pushed the FurcyPin/SPARK-38870 branch from 028298e to a270630 Compare April 26, 2022 08:28
@HyukjinKwon

Copy link
Copy Markdown
Member

Yeah, I don't quite follow it either. Maybe let's fix it together in this PR, merge it and see how it goes.

## Update of previous commits

Fix linter's warnings

For some obscure reason, the CI linting step fails with the following error:

starting mypy examples test...
examples failed mypy checks:
examples/src/main/python/pagerank.py:79: error: unused "type: ignore" comment

This is extremely weird as the pagerank.py seems to be completely
unrelated to the changes made in this ticket.

We removed this "type: ignore" comment to make mypy happy.
@FurcyPin
FurcyPin force-pushed the FurcyPin/SPARK-38870 branch from a270630 to 79323e8 Compare April 28, 2022 08:44
@HyukjinKwon

Copy link
Copy Markdown
Member

Merged to master.

@FurcyPin
FurcyPin deleted the FurcyPin/SPARK-38870 branch March 3, 2023 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants